package productserver.views;

import java.net.MalformedURLException;
import java.rmi.Naming;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.eclipse.jface.layout.TreeColumnLayout;
import org.eclipse.jface.viewers.ColumnLayoutData;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.ui.dialogs.FilteredTree;
import org.eclipse.ui.dialogs.PatternFilter;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.forms.widgets.TableWrapLayout;
import org.eclipse.ui.part.ViewPart;

import productmanagementclient.publish.Product;
import productmanagementclient.publish.ProductRemote;
import productserver.Activator;

public class ProductView extends ViewPart {
	
	public static final String ID = ProductView.class.getName();
	private static final DateFormat TIMESTAMP_FORMAT = new SimpleDateFormat(
			"MM/dd/yyyy"); //$NON-NLS-1$
	
	private static final String[] CLIENTS = new String[] {"client1", "client2", "client3"};

	/**
	 * The filter tree.
	 */
	private FilteredTree filteredTree;

	/**
	 * The tree viewer.
	 */
	private TreeViewer treeViewer;

	/**
	 * The tree.
	 */
	private Tree tree;

	private ProductViewLabelProvider labelProvider = new ProductViewLabelProvider();

	private List<Product> elements;

	private Text productNameText;
	private Text productTypeText;
	private Text noteText;
	private Text importCostText;
	private Text shippingCostText;
	private DateTime importDateText;
	private Text remainingItemsText;
	private Text exportCostText;

	private Button newProductButton;
	private Button cancelButton;
	private Button saveButton;
	private Button deleteButton;

	/** The current sashform. */
	private SashForm sash;

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
	 */
	@Override
	public void createPartControl(Composite parent) {
		elements = new ArrayList<Product>();
		// createDummy();
		GridLayout layout = new GridLayout();
		layout.marginHeight = 0;
		layout.marginWidth = 0;
		layout.numColumns = 1;
		parent.setLayout(layout);

		sash = new SashForm(parent, SWT.NONE);
		sash.setSashWidth(5);
		sash.setOrientation(SWT.VERTICAL);
		GridData gd = new GridData(GridData.FILL_BOTH);
		gd.grabExcessHorizontalSpace = true;
		sash.setLayoutData(gd);
		sash.setLayout(new GridLayout());

		Composite comp = new Composite(sash, SWT.NULL);
		GridLayout gl = new GridLayout(1, false);
		comp.setLayout(gl);

		createTitle(comp);
		createView(comp);
		createProductDetailView(sash);

		sash.setWeights(new int[] { 70, 30 });

		try {
			elements = getProducts();
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		initializeEvents();
		treeViewer.setInput(this);
	}

	private void initializeEvents() {
		cancelButton.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				clearProductDetail();
				onCancel();
				asyncRefresh();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});

		deleteButton.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				onDeleteProduct();
				asyncRefresh();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});

		saveButton.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				onSaveProduct();
				asyncRefresh();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});

		newProductButton.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetSelected(SelectionEvent e) {
				clearProductDetail();
				onNewProduct();
				asyncRefresh();
			}

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}
		});
	}

	private void onNewProduct() {
		// TODO
	}

	private void onSaveProduct() {
		// TODO
	}

	private void onCancel() {
		// TODO
	}

	private void onDeleteProduct() {
		// TODO
	}

	private List<Product> getProducts() throws MalformedURLException,
			RemoteException, NotBoundException {
		System.setProperty("java.security.policy", "security.policy");
		EmployeeSecurityManager mySm = new EmployeeSecurityManager();
		System.setSecurityManager(mySm);

		ProductRemote server = (ProductRemote) Naming
				.lookup("rmi://localhost/client1");
		List<Product> allProduct = server.getAllProduct();
		return allProduct;
	}

	private void createProductDetailView(final Composite parent) {
		Composite composite = new Composite(parent, SWT.BORDER);
		GridLayout gl = new GridLayout();
		gl.numColumns = 4;
		gl.makeColumnsEqualWidth = false;
		composite.setLayout(gl);

		GridData gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		composite.setLayoutData(gd);

		// add group of buttons
		Composite buttons = new Composite(composite, SWT.NONE);
		buttons.setLayout(new FillLayout());
		GridData buttonsGD = new GridData();
		buttonsGD.horizontalSpan = 4;
		buttonsGD.grabExcessHorizontalSpace = true;
		buttons.setLayoutData(buttonsGD);

		newProductButton = new Button(buttons, SWT.NONE);
		newProductButton.setImage(Activator.getImageDescriptor(
				"icons\\add_16x16.gif").createImage());
		newProductButton.setText("New Product");

		cancelButton = new Button(buttons, SWT.NONE);
		cancelButton.setImage(Activator.getImageDescriptor(
				"icons\\cancel_16x16.gif").createImage());
		cancelButton.setText("Cancel");

		saveButton = new Button(buttons, SWT.NONE);
		saveButton.setImage(Activator.getImageDescriptor(
				"icons\\save_16x16.gif").createImage());
		saveButton.setText("Save");

		deleteButton = new Button(buttons, SWT.NONE);
		deleteButton.setImage(Activator.getImageDescriptor(
				"icons\\delete_16x16.gif").createImage());
		deleteButton.setText("Delete");

		// add edit text
		Label productNameLabel = new Label(composite, SWT.NONE);
		productNameLabel.setText("Product Name:");
		productNameText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		productNameText.setLayoutData(gd);

		Label productTypeLabel = new Label(composite, SWT.NONE);
		productTypeLabel.setText("Product Type:");
		productTypeText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		productTypeText.setLayoutData(gd);

		Label noteLabel = new Label(composite, SWT.NONE);
		noteLabel.setText("Note:");
		noteText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		noteText.setLayoutData(gd);

		Label importCostLabel = new Label(composite, SWT.NONE);
		importCostLabel.setText("Import Cost:");
		importCostText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		importCostText.setLayoutData(gd);

		Label shippingLabel = new Label(composite, SWT.NONE);
		shippingLabel.setText("Shipping Cost:");
		shippingCostText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		shippingCostText.setLayoutData(gd);

		Label importDateLabel = new Label(composite, SWT.NONE);
		importDateLabel.setText("Import Date:");
		importDateText = new DateTime(composite, SWT.BORDER | SWT.DATE);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		importDateText.setLayoutData(gd);

		Label remainingItemLabel = new Label(composite, SWT.NONE);
		remainingItemLabel.setText("Remaining Items:");
		remainingItemsText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		remainingItemsText.setLayoutData(gd);

		Label exportCostLabel = new Label(composite, SWT.NONE);
		exportCostLabel.setText("Export Cost:");
		exportCostText = new Text(composite, SWT.BORDER);
		gd = new GridData();
		gd.grabExcessHorizontalSpace = true;
		gd.horizontalAlignment = GridData.FILL;
		exportCostText.setLayoutData(gd);
	}

	private void createTitle(Composite parent) {
		
		Composite comp = new Composite(parent, SWT.NONE);
		GridLayout gl = new GridLayout(2, false);
		comp.setLayout(gl);
		
		Text text = new Text(comp, SWT.NONE);
		text.setText("Select client: ");
		text.setBackground(parent.getBackground());
		
		Combo combo= new Combo(comp, SWT.NONE); //org.eclipse.swt.widgets.Combo
		combo.setLocation(new Point(10, 50));
		combo.setSize(new Point(200, 20));
		combo.setItems(CLIENTS);
		
		FormToolkit toolkit = new FormToolkit(parent.getDisplay());
		toolkit.setBackground(parent.getBackground());

		Form form = toolkit.createForm(parent);
		GridData gd = new GridData(GridData.FILL_HORIZONTAL);
		gd.grabExcessHorizontalSpace = true;
		gd.grabExcessVerticalSpace = false;
		form.setLayoutData(gd);
		form.getBody().setLayout(new TableWrapLayout());
		// form.setFont(parent.getFont());
		form.setText("Product Management");
		toolkit.decorateFormHeading(form);
	}

	/**
	 * Create the tree viewer.
	 * 
	 * @param parent
	 *            the parent composite
	 */
	private void createView(final Composite parent) {
		filteredTree = new ProductTree(parent);

		treeViewer = filteredTree.getViewer();
		treeViewer.setUseHashlookup(true);
		tree = treeViewer.getTree();
		treeViewer.setContentProvider(new ProductViewContentProvider());
		treeViewer.setLabelProvider(labelProvider);

		treeViewer.setInput(this);

		createColumns();
		tree.addMouseListener(new MouseListener() {

			@Override
			public void mouseUp(MouseEvent e) {
			}

			@Override
			public void mouseDown(MouseEvent e) {
			}

			@Override
			public void mouseDoubleClick(MouseEvent e) {
				IStructuredSelection ss = (IStructuredSelection) treeViewer
						.getSelection();
				Product product = (Product) ss.getFirstElement();
				if (product != null) {
					fillProductDetail(product);
				}
			}
		});
		tree.setLinesVisible(true);
		tree.setHeaderVisible(true);
	}

	@SuppressWarnings("deprecation")
	private void fillProductDetail(Product product) {
		productNameText.setText(product.getName() != null ? product.getName()
				: "");
		productTypeText.setText(product.getProductType() != null ? product
				.getProductType() : "");
		noteText.setText(product.getNote() != null ? product.getNote() : "");
		int year = new Date().getYear();
		int month = new Date().getMonth();
		int date = new Date().getDate();
		if (product.getImportDate() != null) {
			year = product.getImportDate().getYear();
			month = product.getImportDate().getMonth();
			date = product.getImportDate().getDate();
		}
		importDateText.setDate(year, month, date);
		importCostText.setText(product.getImportCost() != null ? Double
				.toString(product.getImportCost()) : "0");
		exportCostText.setText(product.getExportCost() != null ? Double
				.toString(product.getExportCost()) : "0");
		shippingCostText.setText(product.getShippingCost() != null ? Double
				.toString(product.getShippingCost()) : "0");
		remainingItemsText.setText(product.getRemainingItem() != null ? Integer
				.toString(product.getRemainingItem()) : "0");
	}

	private void clearProductDetail() {
		Date date = new Date();
		productNameText.setText("");
		productTypeText.setText("");
		noteText.setText("");
		importCostText.setText("");
		shippingCostText.setText("");
		importDateText.setDate(date.getYear(), date.getMonth(), date.getDate());
		remainingItemsText.setText("");
		exportCostText.setText("");
	}

	/**
	 * define all columns in the tree.
	 */
	private void createColumns() {
		TreeColumnLayout treeLayout = new TreeColumnLayout();
		tree.getParent().setLayout(treeLayout);

		ColumnSorter sorter = null;
		for (ProductTableColumn item : ProductTableColumn.values()) {
			TreeColumn column = new TreeColumn(tree, item.getColumnStyle());
			column.setText(item.toString());
			ColumnLayoutData layoutData = item.getLayoutData();
			column.setResizable(layoutData.resizable);
			treeLayout.setColumnData(column, layoutData);
			sorter = new ColumnSorter(filteredTree.getViewer(), column) {
				@Override
				public String getColumnText(final Object obj,
						final int columnIndex) {
					return ProductView.this.labelProvider.getColumnText(obj,
							columnIndex);
				}
			};
			if (item == ProductTableColumn.PRODUCT_TYPE) {
				sorter.setDirection(SWT.UP);
			}
		}
	}

	/**
	 * Label provider for the viewer.
	 */
	private static class ProductViewLabelProvider extends LabelProvider
			implements ITableLabelProvider {

		/**
		 * {@inheritDoc}
		 */
		public String getColumnText(final Object obj, final int index) {
			ProductTableColumn column = ProductTableColumn.valueOf(index);
			if (!(obj instanceof Product) || column == null) {
				return null;
			}

			Product product = (Product) obj;
			String columnText = null;

			switch (column) {
			case ID:
				columnText = Long.toString(product.getId());
				break;
			case PRODUCT_NAME:
				columnText = product.getName();
				break;
			case PRODUCT_TYPE:
				columnText = product.getProductType();
				break;

			case REMANING_ITEMS:
				columnText = product.getRemainingItem() != null ? Integer
						.toString(product.getRemainingItem()) : "";
				break;
			case COST:
				columnText = product.getExportCost() != null ? Double
						.toString(product.getExportCost()) : "";
				break;
			case IMPORT_DATE:
				columnText = product.getImportDate() != null ? TIMESTAMP_FORMAT
						.format(product.getImportDate()) : "";
				break;
			default:
				break;
			}
			return columnText;
		}

		/**
		 * {@inheritDoc}
		 */
		public Image getColumnImage(final Object element, final int columnIndex) {
			return null;
		}

		/**
		 * {@inheritDoc}
		 */
		@Override
		public String getText(final Object element) {
			return element.toString();
		}
	}

	/**
	 * An inner class to provide contents for the tree viewer.
	 */
	class ProductViewContentProvider implements ITreeContentProvider {

		/**
		 * {@inheritDoc}
		 */
		public void inputChanged(final Viewer v, final Object oldInput,
				final Object newInput) {
			// no-op
		}

		/**
		 * {@inheritDoc}
		 */
		public void dispose() {
		}

		/**
		 * {@inheritDoc}
		 */
		public Object[] getElements(final Object parent) {
			return elements.toArray(new Product[elements.size()]);
		}

		/**
		 * {@inheritDoc}
		 * 
		 * @see org.eclipse.jface.viewers.ITreeContentProvider#getChildren(java.lang
		 *      .Object)
		 */
		public Object[] getChildren(final Object parentElement) {
			return null;
		}

		/**
		 * {@inheritDoc}
		 * 
		 * @see org.eclipse.jface.viewers.ITreeContentProvider#getParent(java.lang
		 *      .Object)
		 */
		public Object getParent(final Object element) {
			if (element instanceof Product) {
				return ProductView.this;
			}
			return null;
		}

		/**
		 * {@inheritDoc}
		 * 
		 * @see org.eclipse.jface.viewers.ITreeContentProvider#hasChildren(java.lang
		 *      .Object)
		 */
		public boolean hasChildren(final Object element) {
			return false;
		}
	}

	/**
	 * Definition for all columns in the properties table.
	 */
	private static enum ProductTableColumn {
		ID("Product ID", 45, 50), PRODUCT_NAME("Product Name", 20, 100), PRODUCT_TYPE(
				"Product Type", 10, 100), REMANING_ITEMS("Remaining Items", 10,
				150), COST("Cost", 25, 100), IMPORT_DATE("Import Date", 25, 100);

		/**
		 * The translation text which will display on the table header.
		 */
		private final String title;

		/**
		 * The column layout data.
		 */
		private final ColumnLayoutData layoutData;

		/**
		 * Construct new instance of PropertiesTableColumn.
		 * 
		 * @param text
		 *            translation text
		 * @param weight
		 *            the weight of the column
		 * @param minimumWidth
		 *            the minimum width of the column in pixels
		 */
		private ProductTableColumn(final String text, final int weight,
				final int minimumWidth) {
			this.title = text;
			this.layoutData = new ColumnWeightData(weight, minimumWidth);
		}

		/**
		 * {@inheritDoc}
		 * 
		 * @see java.lang.Enum#toString()
		 */
		@Override
		public String toString() {
			return title;
		}

		/**
		 * Method to get column style.
		 * 
		 * @return style
		 */
		public int getColumnStyle() {
			return SWT.LEFT;
		}

		/**
		 * Method to get the layoutData.
		 * 
		 * @return the layoutData
		 */
		public ColumnLayoutData getLayoutData() {
			return layoutData;
		}

		/**
		 * Method to find {@link PropertiesTableColumn} from its index.
		 * 
		 * @param index
		 *            index
		 * @return <code>null</code> if there are no items with that index
		 */
		private static ProductTableColumn valueOf(final int index) {
			for (ProductTableColumn item : values()) {
				if (item.ordinal() == index) {
					return item;
				}
			}
			return null;
		}
	}

	/**
	 * The error tree.
	 * 
	 * @author hieu.tranvan@vn.bosch.com
	 */
	private class ProductTree extends FilteredTree {
		/**
		 * Construct new instance of ErrorTree.
		 * 
		 * @param parent
		 *            the parent composite
		 */
		public ProductTree(final Composite parent) {
			super(parent, SWT.MULTI | SWT.FULL_SELECTION | SWT.BORDER,
					new ProductFilter(), true);

			setBackground(parent.getDisplay().getSystemColor(
					SWT.COLOR_LIST_BACKGROUND));

			Text filterControl = getFilterControl();
			Composite filterComposite = filterControl.getParent();
			GridData gd = (GridData) filterComposite.getLayoutData();
			gd.verticalIndent = 2;
			gd.horizontalIndent = 1;
		}
	}

	/**
	 * The error filter for Error list view.
	 * 
	 * @author hieu.tranvan@vn.bosch.com
	 * 
	 */
	private class ProductFilter extends PatternFilter {
		/**
		 * Construct new instance of ErrorFilter.
		 */
		public ProductFilter() {
			super();
			setIncludeLeadingWildcard(true);
		}
	}

	/**
	 * {@inheritDoc}
	 * 
	 * @see org.eclipse.ui.part.WorkbenchPart#setFocus()
	 */
	@Override
	public void setFocus() {

	}

	/**
	 * Method to asynchronous refresh elements in view.
	 */
	private void asyncRefresh() {
		if (tree.isDisposed()) {
			return;
		}
		Display display = tree.getDisplay();
		if (display != null) {
			display.asyncExec(new Runnable() {
				public void run() {
					if (!tree.isDisposed()) {
						treeViewer.refresh();
					}
				}
			});
		}
	}
}
